﻿using System;
using System.Collections;
using System.Configuration;
using System.Reflection;
using System.Web;
using System.Web.Configuration;
using System.Web.UI.WebControls;

namespace Salient.Web.Administration.Providers
{
    public partial class ManageConsolidatedProviders : ProvidersPage
    {
        private int _parentProviderCount;

        public string CurrentProvider
        {
            get { return (string) Session["WebAdminManageConsolidatedProvidersCurrentProvider"]; }
            set { Session["WebAdminManageConsolidatedProvidersCurrentProvider"] = value; }
        }

        public void BackToPreviousPage(object sender, EventArgs e)
        {
            ReturnToPreviousPage(sender, e);
        }

        private void BindProviderList(ProviderList providerList)
        {
            string appPath = ApplicationPath;
            int trailingSlash = appPath.LastIndexOf("/");
            string parentAppPath = appPath.Substring(0, trailingSlash);
            if (parentAppPath != null && parentAppPath.Length == 0)
            {
                parentAppPath = null;
            }

            System.Configuration.Configuration config = OpenWebConfiguration(appPath);
            var membershipSection = (MembershipSection) config.GetSection("system.web/membership");
            var roleManagerSection = (RoleManagerSection) config.GetSection("system.web/roleManager");

            System.Configuration.Configuration parentConfig = OpenWebConfiguration(parentAppPath);
            var membershipParentSection = (MembershipSection) parentConfig.GetSection("system.web/membership");
            var roleManagerParentSection = (RoleManagerSection) parentConfig.GetSection("system.web/roleManager");

            var providersArray = new ArrayList();
            var groupedProvidersFiltered = new ArrayList();

            ProviderSettingsCollection membershipProviders = membershipSection.Providers;
            ProviderSettingsCollection roleManagerProviders = roleManagerSection.Providers;

            ProviderSettingsCollection membershipParentProviders = membershipParentSection.Providers;
            ProviderSettingsCollection roleManagerParentProviders = roleManagerParentSection.Providers;

            var connectionStringSection = (ConnectionStringsSection) config.GetSection("connectionStrings");

            // loop thru the membershipProviders and see if our grouped entries are in there
            // if so, then grab the connection string, it must be the same for the role provider as well
            foreach (ProviderSettings mps in membershipProviders)
            {
                string name = mps.Name;
                string connectionString = mps.Parameters["connectionStringName"];

                foreach (GroupedProperty oneGroupedProvider in GroupedProvidersList)
                {
                    if (name == oneGroupedProvider.MembershipProvider)
                    {
                        // check if the roleprovider exists with the identical connection string
                        if (HasProviderInProviderSettings(roleManagerProviders, oneGroupedProvider.RoleProvider,
                                                          connectionString))
                        {
                            groupedProvidersFiltered.Add(oneGroupedProvider);

                            string tempDescription = oneGroupedProvider.Description;

                            // use the type from the membership provider for the test link...
                            providersArray.Add(new ProviderList.ProviderListItems(oneGroupedProvider.Name,
                                                                                  tempDescription, connectionString,
                                                                                  mps.Type, true));
                        }
                    }
                }
            }

            foreach (ProviderSettings mps in membershipProviders)
            {
                string name = mps.Name;
                string connectionString = mps.Parameters["connectionStringName"];

                if (HasProviderInProviderSettings(roleManagerProviders, name, connectionString))
                {
                    // Check if the same provider shows up in the parent config.
                    if (HasProviderInProviderSettings(membershipParentProviders, name, connectionString) &&
                        HasProviderInProviderSettings(roleManagerParentProviders, name, connectionString))
                    {
                        _parentProviderCount++;
                    }

                    providersArray.Add(new ProviderList.ProviderListItems(mps.Name, mps.Parameters["description"],
                                                                          mps.Parameters["connectionStringName"],
                                                                          mps.Type, false));
                }
            }

            providerList.DataSource = providersArray;

            providerList.ParentProviderCount = _parentProviderCount;
            string defaultMembershipProvider = membershipSection.DefaultProvider;
            string defaultRoleProvider = roleManagerSection.DefaultProvider;

            if (defaultMembershipProvider == defaultRoleProvider)
            {
                for (int i = 0; i < providersArray.Count; i++)
                {
                    if (((ProviderList.ProviderListItems) providersArray[i]).ProviderName == defaultMembershipProvider)
                    {
                        providerList.SelectedIndex = i;
                    }
                }
                Session["DefaultProvider"] = defaultMembershipProvider;
            }
            else
            {
                // check if they are part of a group and select that group
                string groupProviderName = String.Empty;
                foreach (GroupedProperty oneGroupedProvider in groupedProvidersFiltered)
                {
                    if (oneGroupedProvider.MembershipProvider == defaultMembershipProvider)
                    {
                        if (oneGroupedProvider.RoleProvider == defaultRoleProvider)
                        {
                            groupProviderName = oneGroupedProvider.Name;

                            for (int i = 0; i < providersArray.Count; i++)
                            {
                                if (((ProviderList.ProviderListItems) providersArray[i]).ProviderName ==
                                    groupProviderName)
                                {
                                    providerList.SelectedIndex = i;
                                }
                            }
                            Session["DefaultProvider"] = groupProviderName;
                        }
                    }
                }
            }

            providerList.DataBind();
        }

        private void BindProviderLists()
        {
            BindProviderList(ProviderList);
        }

        private bool HasProviderInProviderSettings(ProviderSettingsCollection providerSettings, string name,
                                                   string connectionString)
        {
            bool found = false;
            foreach (ProviderSettings ps in providerSettings)
            {
                if (ps.Name == name && ps.Parameters["connectionStringName"] == connectionString)
                {
                    found = true;
                    break;
                }
            }
            return found;
        }

        private void Page_Load()
        {
            if (!IsPostBack)
            {
                BindProviderLists();
            }
        }

        public void SelectProvider(object sender, ProviderList.ProviderEventArgs e)
        {
            var radioButton = (RadioButton) sender;
            System.Configuration.Configuration config = OpenWebConfiguration(ApplicationPath);

            var membershipSection = (MembershipSection) config.GetSection("system.web/membership");
            var roleManagerSection = (RoleManagerSection) config.GetSection("system.web/roleManager");

            if (e.IsGroup)
            {
                // lookup the group and set the appropriate providers.
                foreach (GroupedProperty oneGroupedProvider in GroupedProvidersList)
                {
                    if (e.ProviderName == oneGroupedProvider.Name)
                    {
                        if (oneGroupedProvider.MembershipProvider != null)
                        {
                            membershipSection.DefaultProvider = oneGroupedProvider.MembershipProvider;
                        }
                        else
                        {
                            membershipSection.DefaultProvider = null;
                        }
                        if (oneGroupedProvider.RoleProvider != null)
                        {
                            roleManagerSection.DefaultProvider = oneGroupedProvider.RoleProvider;
                        }
                        else
                        {
                            roleManagerSection.DefaultProvider = null;
                        }
                    }
                }
            }
            else
            {
                membershipSection.DefaultProvider = e.ProviderName;
                roleManagerSection.DefaultProvider = e.ProviderName;
            }

            SaveConfig(config);
            BindProviderLists();
        }

        private bool TestConnectionHelper(string connection)
        {
            bool good = true;
            try
            {
                Type type = typeof (HttpApplication).Assembly.GetType("System.Web.DataAccess.SqlConnectionHelper");
                MethodInfo method = type.GetMethod("GetConnection",
                                                   BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
                if (method != null)
                {
                    method.Invoke(null, new object[] {connection, false /* revert impersonation */});
                }
            }
            catch
            {
                good = false;
            }
            return good;
        }

        private bool TestConnectionString(object sender, EventArgs e)
        {
            var b = sender as LinkButton;
            string connectionString = null;
            try
            {
                System.Configuration.Configuration config = OpenWebConfiguration(ApplicationPath);
                var connectionStringSection = (ConnectionStringsSection) config.GetSection("connectionStrings");
                // Review: Management API doesn't allow retrieve a connection string setting via direct name look up
                // Need to create an object with the name set for looking up instead.
                var css = new ConnectionStringSettings();
                css.Name = b.CommandArgument /* connection string name */;
                css = connectionStringSection.ConnectionStrings[connectionStringSection.ConnectionStrings.IndexOf(css)];
                connectionString = css.ConnectionString;
            }
            catch
            {
                return false;
            }
            if (b.CommandName.Contains("Sql"))
            {
                return TestConnectionHelper(connectionString);
            }
            else
            {
                return true;
            }
        }

        public void TestConnection(object sender, EventArgs e)
        {
            bool good = TestConnectionString(sender, e);
            var b = (LinkButton) sender;
            bool isSql = b.CommandName.Contains("Sql");

            mv1.ActiveViewIndex = 1;
            testConnectionLiteral.Text = TestConnectionText(good, isSql);

            OKButton.Visible = true;
            ((WebAdminWithConfirmation) Master).SetDisplayUI(true /* confirmation */);
        }

        public void OK_Click(object sender, EventArgs e)
        {
            ((WebAdminWithConfirmation) Master).SetDisplayUI(false);
        }
    }
}